
package column


import (
	"github.com/treelab/updatecolumn/models"
)

  func instanceType() int32 {
    return models.Lookup
  }


  deleteColumnEdges(command: UpdateColumn_v2, o: CommonOptions) {
    const { column } = command;
    o.delQuads.push(
      ...this.dgraphHelperService.getRemoveEdgeQuads(column.uid!, [
        'foreignLookupColumnId',
        'recordReferenceColumnId',
        Relation.HAS_FOREIGN_LOOKUP_COLUMN,
        Relation.HAS_RECORD_REFERENCE_COLUMN,
        'errorCode',
      ]),
    );
    o.delQuads.push(
      ...this.dgraphHelperService.getRemoveEdgeQuads(
        column.foreignLookupColumnId,
        [Relation.HAS_LOOKUP_UPDATE],
        column.uid,
      ),
    );
    o.delQuads.push(
      ...this.dgraphHelperService.getRemoveEdgeQuads(
        column.recordReferenceColumnId,
        [Relation.HAS_LOOKUP_COLUMN],
        column.uid,
      ),
    );
    return this;
  }

  public hasNothingToUpdate(command: UpdateColumn_v2) {
    const { column } = command;
    const lookupColumnConfig = command.columnConfig as LookupColumnConfig;
    const result =
      column.columnType === this.instanceType &&
      column.foreignLookupColumnId === lookupColumnConfig.foreignLookupColumnId &&
      column.recordReferenceColumnId === lookupColumnConfig.recordReferenceColumnId &&
      !column.errorCode;
    return result;
  }

  async updateColumn(
    command: UpdateColumn_v2,
    o: CommonOptions,
    helper: { rows?: Row[]; columnCopy?: Column; referenceColumns?: Column[]; userGroup?: any },
  ) {
    await super.updateColumn(command, o, helper);

    const { column, columnConfig } = command;
    const { recordReferenceColumnId, foreignLookupColumnId, errorCode } = columnConfig as LookupColumnConfig;

    // TODO: validate the above two column ids

    column.foreignLookupColumnId = foreignLookupColumnId;
    column.recordReferenceColumnId = recordReferenceColumnId;
    if (errorCode) {
      column.errorCode = errorCode;
    } else {
      const foreignLookupColumn = o!.ormTransaction.nodeFor(Column, { uid: foreignLookupColumnId });
      column.hasForeignLookupColumn.add(foreignLookupColumn);
      foreignLookupColumn.hasLookupUpdate.add(column);

      const recordReferenceColumn = o!.ormTransaction.nodeFor(Column, { uid: recordReferenceColumnId });
      column.hasRecordReferenceColumn.add(recordReferenceColumn);
      recordReferenceColumn.hasLookupColumn.add(column);
    }
    return this;
  }

  async convertColumn(
    command: UpdateColumn_v2,
    o: CommonOptions,
    helper: { rows?: Row[]; columnCopy?: Column; referenceColumns?: Column[]; userGroup?: any },
  ) {
    const { column } = command;
    const lookupConfig = command.columnConfig as LookupColumnConfig;
    const { foreignLookupColumnId, recordReferenceColumnId } = lookupConfig;
    if (
      foreignLookupColumnId === column.foreignLookupColumnId &&
      recordReferenceColumnId === column.recordReferenceColumnId &&
      !column.errorCode
    ) {
      return this;
    }

    let foreignLookupColumn: Column;
    const columnORMTransaction = await this.columnReadService.getColumnAllColumnObjByColumnIds(
      [foreignLookupColumnId, recordReferenceColumnId],
      { includeCell: true },
    );
    const columns = columnORMTransaction.tree;
    columns.forEach(_column => {
      if (_column.uid === foreignLookupColumnId) {
        foreignLookupColumn = _column;
      }
    });
    if (!foreignLookupColumn!) {
      throw new ColumnNotExistError(foreignLookupColumnId);
    }
    const { errorCode } = foreignLookupColumn!;

    if (errorCode) {
      throw new LookupColumnInvalidError(foreignLookupColumnId);
    }
    const symmetricColumn = await this.getEdges(recordReferenceColumnId, Relation.HAS_SYMMETRIC_COLUMN);
    this.isSelfReference(symmetricColumn ? symmetricColumn[0] : undefined, lookupConfig);
    await this.checkCircularReference(command.tableId, foreignLookupColumn!.uid!);

    await this.defaultConvert({ command }, o, helper);

    const columnOptions = this.getColumnTypeOptions(column, foreignLookupColumn!, lookupConfig);
    o.events.addEvents(
      new LookupColumnConfigUpdated(
        command.workspaceId,
        command.coreId,
        command.tableId,
        column.uid!,
        JSON.parse(columnOptions.typeOptions),
        command._metadata,
      ),
    );
    return this;
  }

  public getColumnTypeOptions(
    column: Column,
    foreignLookupColumn: Column,
    columnConfig?: any,
  ): { name: any; type: any; typeOptions: string } {
    if (columnConfig) {
      const { name: columnName } = columnConfig;
      const { recordReferenceColumnId: lookupRecordReferenceColumnId } = columnConfig as LookupColumnConfig;
      const _lookupTypeOptions = this.getLookupTypeOptions(foreignLookupColumn, lookupRecordReferenceColumnId);
      return { name: columnName, type: ColumnType.LOOKUP, typeOptions: _lookupTypeOptions };
    }
    const result = super.getColumnTypeOptions(column, columnConfig);

    const { errorCode, recordReferenceColumnId } = column;
    if (errorCode === ColumnErrorCodes.LOOKUP_COLUMN_REMOVED) {
      return {
        name: column?.name,
        type: ColumnType.LOOKUP,
        typeOptions: JSON.stringify({
          errorCode: ColumnErrorCodes.LOOKUP_COLUMN_REMOVED,
        }),
      };
    }
    const lookupTypeOptions = this.getLookupTypeOptions(foreignLookupColumn, recordReferenceColumnId);
    return Object.assign(result, { type: ColumnType.LOOKUP, typeOptions: lookupTypeOptions });
  }

  private getLookupTypeOptions(foreignLookupColumn: Column, recordReferenceColumnId: string) {
    if (!foreignLookupColumn.columnType || foreignLookupColumn.errorCode) {
      if (foreignLookupColumn.errorCode === ColumnErrorCodes.LOOKUP_COLUMN_REMOVED) {
        return JSON.stringify({ errorCode: ColumnErrorCodes.LOOKUP_COLUMN_REMOVED });
      } else if (foreignLookupColumn.errorCode === ColumnErrorCodes.ROLLUP_COLUMN_REMOVED) {
        return JSON.stringify({ errorCode: ColumnErrorCodes.ROLLUP_COLUMN_REMOVED });
      }
      return JSON.stringify({ errorCode: ColumnErrorCodes.TYPE_INVALID_ERROR });
    }
    const getNestedColumn = (column: Column): Column =>
      column.columnType === ColumnType.LOOKUP ? getNestedColumn(column.hasForeignLookupColumn.get()[0]) : column;
    const nestedColumn = getNestedColumn(foreignLookupColumn);
    const {
      columnType: lookupColumnType,
      idFormat: lookupIdFormat,
      idPrefix: lookupIdPrefix,
      formula: lookupFormula,
      resultType: lookupResultType,
      foreignWorkspaceId: lookupForeignWorkspaceId,
      foreignCoreId: lookupForeignCoreId,
      foreignTableId: lookupForeignTableId,
      oneToOne: lookupOneToOne,
      recordReferenceColumnId: lookupRecordReferenceColumnId,
      symmetricColumnId: lookupSymmetricColumnId,
      useGMT: lookupUseGMT,
      timeFormat: lookupTimeFormat,
      includeTime: lookupIncludeTime,
      dateFormat: lookupDateFormat,
      currencyFormat: lookupCurrencyFormat,
      ratingStyle: lookupRatingStyle,
      ratingMax: lookupRatingMax,
      precision: lookupPrecision,
      numberFormat: lookupNumberFormat,
      useNotify: lookupUseNotify,
      useGroup: lookupUseGroup,
      useMultiple: lookupUseMultiple,
    } = nestedColumn;
    const lookupOptions = nestedColumn.hasColumnOption.get();
    const lookupTypeOptions = {
      lookupColumnType,
      foreignLookupColumnId: foreignLookupColumn.uid!,
      recordReferenceColumnId,
    };
    let typeSpecificOption = {};
    switch (lookupColumnType) {
      case ColumnType.PHONE:
      case ColumnType.EMAIL:
      case ColumnType.TEXT:
        break;
      case ColumnType.LONG_TEXT:
        break;
      case ColumnType.MULTI_ATTACHMENT:
        break;
      case ColumnType.DATETIME: {
        typeSpecificOption = {
          lookupUseGMT,
          lookupTimeFormat,
          lookupIncludeTime,
          lookupDateFormat,
        };
        break;
      }
      case ColumnType.NUMBER: {
        typeSpecificOption = { lookupPrecision };
        break;
      }
      case ColumnType.CURRENCY: {
        typeSpecificOption = {
          lookupCurrencyFormat,
          lookupPrecision,
        };
        break;
      }
      case ColumnType.CHECKBOX: {
        break;
      }
      case ColumnType.SELECT:
      case ColumnType.MULTI_SELECT:
        typeSpecificOption = {
          lookupOptions: (lookupOptions || []).map((option, index) => ({
            optionId: option.uid,
            name: option.name,
            color: option.color,
            order: index,
          })),
        };
        break;
      case ColumnType.RATING: {
        typeSpecificOption = {
          lookupRatingStyle,
          lookupRatingMax,
        };
        break;
      }
      case ColumnType.RECORD_REFERENCE: {
        typeSpecificOption = {
          lookupForeignWorkspaceId,
          lookupForeignCoreId,
          lookupForeignTableId,
          lookupOneToOne,
          lookupSymmetricColumnId,
        };
        break;
      }
      case ColumnType.UNIQUE_ID: {
        typeSpecificOption = { lookupIdPrefix, lookupIdFormat };
        break;
      }
      case ColumnType.FORMULA: {
        typeSpecificOption = {
          lookupFormula,
          lookupResultType: lookupResultType || FormulaResultType.TEXT,
          lookupNumberFormat,
          lookupPrecision,
          lookupCurrencyFormat,
          lookupDateFormat,
          lookupTimeFormat,
          lookupIncludeTime,
          lookupUseGMT,
        };
        break;
      }
      case ColumnType.ROLLUP: {
        typeSpecificOption = {
          lookupFormula,
          lookupRecordReferenceColumnId,
          lookupResultType: lookupResultType || FormulaResultType.TEXT,
          lookupNumberFormat,
          lookupPrecision,
          lookupCurrencyFormat,
          lookupDateFormat,
          lookupTimeFormat,
          lookupIncludeTime,
          lookupUseGMT,
        };
        break;
      }
      case ColumnType.COLLABORATOR:
        typeSpecificOption = {
          lookupUseNotify,
          lookupUseGroup,
          lookupUseMultiple,
        };
        break;
      default:
        throw new Error(`Unsupported column type ${lookupColumnType}`);
    }
    const cache: any = [];
    return JSON.stringify({ ...lookupTypeOptions, ...typeSpecificOption }, (key, value) => {
      if (typeof value === 'object' && value !== null) {
        if (cache.indexOf(value) !== -1) {
          return;
        }
        cache.push(value);
      }
      return value;
    });
  }

